﻿using AutoMapper;
using QYmall.Core.Common.Emum;
using QYmall.Core.Common.Extensions;
using QYmall.Core.Common.Helper;
using QYmall.Core.DBFactory.Database;
using QYmall.Core.IServices;
using QYmall.Core.IServices.Alipay;
using QYmall.Core.IServices.WeChat;
using QYmall.Core.Model.Models;
using QYmall.Core.Model.ViewModels;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace QYmall.Core.Services
{
    /// <summary>
    /// 商品退换货接口实现
    /// </summary>
    public class OrderRefundService : BaseService, IOrderRefundService
    {
        private readonly IWeChatExecuteService _weChatExecuteService;
        private readonly IAlipayExecuteService _alipayExecuteService;
        private readonly IUserService _userService;
        private readonly IMapper _mapper;

        public OrderRefundService(IDbContextFactory contentFactory,
            IWeChatExecuteService weChatExecuteService, IAlipayExecuteService alipayExecuteService,
            IUserService userService, IMapper mapper) : base(contentFactory)
        {
            _weChatExecuteService = weChatExecuteService;
            _alipayExecuteService = alipayExecuteService;
            _userService = userService;
            _mapper = mapper;
        }

        /// <summary>
        /// 查询一条记录
        /// </summary>
        public async Task<OrderRefund?> QueryAsync(Expression<Func<OrderRefund, bool>> funcWhere, WriteRoRead writeAndRead = WriteRoRead.Read)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库
            var result = await _context.Set<OrderRefund>()
                .Include(x => x.RefundGoods).ThenInclude(x => x.OrderGoods)
                .Include(x => x.RefundAlbums)
                .FirstOrDefaultAsync(funcWhere);
            return result;
        }

        /// <summary>
        /// 查询指定数量列表
        /// </summary>
        public async Task<IEnumerable<OrderRefund>> QueryListAsync(int top, Expression<Func<OrderRefund, bool>> funcWhere,
            string orderBy, WriteRoRead writeAndRead = WriteRoRead.Read)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库
            var result = _context.Set<OrderRefund>()
                .Include(x => x.RefundGoods).ThenInclude(x => x.OrderGoods)
                .Include(x => x.RefundAlbums)
                .Where(funcWhere).OrderByBatch(orderBy);//调用Linq扩展类进行排序
            if (top > 0) result = result.Take(top);//等于0显示所有数据
            return await result.ToListAsync();
        }

        /// <summary>
        /// 查询分页列表
        /// </summary>
        public async Task<PaginationList<OrderRefund>> QueryPageAsync(int pageSize, int pageIndex, Expression<Func<OrderRefund, bool>> funcWhere,
            string orderBy, WriteRoRead writeAndRead = WriteRoRead.Read)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库
            var result = _context.Set<OrderRefund>()
                .Include(x => x.RefundGoods).ThenInclude(x => x.OrderGoods)
                .Include(x => x.RefundAlbums)
                .Where(funcWhere).OrderByBatch(orderBy);//调用Linq扩展类排序
            return await PaginationList<OrderRefund>.CreateAsync(pageIndex, pageSize, result);
        }

        /// <summary>
        /// 获取记录总数量
        /// </summary>
        public async Task<int> QueryCountAsync(Expression<Func<OrderRefund, bool>> funcWhere, WriteRoRead writeAndRead = WriteRoRead.Read)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库
            return await _context.Set<OrderRefund>().Where(funcWhere).CountAsync();
        }

        /// <summary>
        /// 申请退换货(客户)
        /// </summary>
        public async Task<bool> ApplyAsync(OrderRefundApplyDto modelDto, WriteRoRead writeAndRead = WriteRoRead.Write)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库

            //检查是否重复提交申请
            if (await _context.Set<OrderRefund>().FirstOrDefaultAsync(x => x.UserId == modelDto.UserId
                && x.OrderId == modelDto.OrderId && x.HandleStatus < 3) != null)
            {
                throw new ResponseException("已有申请尚未处理，请勿重复提交");
            }
            //查找订单信息
            var orderModel = await _context.Set<Orders>().FirstOrDefaultAsync(x => x.UserId == modelDto.UserId && x.Id == modelDto.OrderId);
            if (orderModel == null)
            {
                throw new ResponseException("订单不存在或已删除，请检查重试");
            }
            //检查订单是否已过售后期
            if (orderModel.IsSettle == 1)
            {
                throw new ResponseException("订单已过售后期限，无法发起退换货");
            }
            //换货：未发货时不能发起换货申请
            if (modelDto.Type == 2 && orderModel.DeliveryStatus == 0)
            {
                throw new ResponseException("订单未发货，请勿申请换货");
            }
            //退款：订单金额等于零时无法发起退款申请
            if (modelDto.Type == 1 && orderModel.OrderAmount <= 0)
            {
                throw new ResponseException("订单金额须大于零才能申请退款");
            }
            //映射成实体
            var model = _mapper.Map<OrderRefund>(modelDto);
            model.OrderNo = orderModel.OrderNo;
            model.MerchantId = orderModel.MerchantId;
            model.UserId = orderModel.UserId;
            model.UserName = orderModel.UserName;
            model.ApplyTime = DateTime.Now;
            //保存数据
            await _context.Set<OrderRefund>().AddAsync(model);
            return await this.SaveAsync();
        }

        /// <summary>
        /// 2.卖家处理:同意,拒绝,退款
        /// </summary>
        public async Task<bool> HandleAsync(Expression<Func<OrderRefund, bool>> funcWhere, OrderRefundHandleDto modelDto, WriteRoRead writeAndRead = WriteRoRead.Write)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库

            var model = await _context.Set<OrderRefund>().Include(x => x.RefundGoods).FirstOrDefaultAsync(funcWhere);
            if (model == null)
            {
                throw new ResponseException($"数据不存在或已删除");
            }
            //退款
            if (model.Type == 1)
            {
                //如果是大于0则已处理，提示错误
                if (model.HandleStatus > 0)
                {
                    throw new ResponseException("单据已处理，请勿重复操作");
                }
                //同意退款
                if (modelDto.HandleStatus == 3)
                {
                    //查询订单状态
                    var orderModel = await _context.Set<Orders>()
                        .Include(x=>x.CollectionRelations).ThenInclude(x=>x.Collection)
                        .Include(x => x.OrderGoods).FirstOrDefaultAsync(x => x.Id == model.OrderId);
                    //订单未付款提示错误
                    if (orderModel?.PaymentStatus != 2)
                    {
                        throw new ResponseException($"订单尚未全额收款，请确认签收后操作");
                    }
                    //退款金额大于订单金额时提示错误
                    if (modelDto.RefundAmount > orderModel.SettleAmount)
                    {
                        throw new ResponseException("退款金额不能大于订单金额");
                    }
                    //把退货订单商品ID转换成列表以便对比
                    var refundIds = model.RefundGoods.Select(x => x.OrderGoodsId);
                    //新增记录器，记录是否已全部退款或部分退款
                    bool isAllRefund = true;
                    //遍历订单货品
                    foreach (var item in orderModel.OrderGoods)
                    {
                        if (refundIds.Contains(item.Id))
                        {
                            item.DeliveryStatus = 2;
                        }
                        else if (item.DeliveryStatus < 2)
                        {
                            isAllRefund = false;
                        }
                    }
                    //映射到实体
                    _mapper.Map(modelDto, model);

                    //如果退款到会员账户则增加会员余额
                    if (model.RefundMode == 1)
                    {
                        //修改会员余额
                        var memberModel = await _context.Set<Members>().FirstOrDefaultAsync(x => x.UserId == model.UserId);
                        if(memberModel == null)
                        {
                            throw new ResponseException($"无法找到该会员信息");
                        }
                        memberModel.Amount += model.RefundAmount;
                        _context.Set<Members>().Update(memberModel);
                        //新增余额记录
                        await _context.Set<MemberAmountLog>().AddAsync(new MemberAmountLog()
                        {
                            UserId = model.UserId,
                            Value = model.RefundAmount,
                            Remark = $"订单[{orderModel.OrderNo}]退款",
                            AddTime = DateTime.Now
                        });
                    }
                    
                    //如果退款是原路返回则调用退款接口
                    if (model.RefundMode == 2)
                    {
                        if (orderModel.CollectionRelations.Count == 0)
                        {
                            throw new ResponseException("无法找到收款记录，请检查重试。");
                        }
                        //检查是否存在多次收款
                        if (orderModel.CollectionRelations.Count > 1)
                        {
                            throw new ResponseException("此订单分多次付款，无法原路返回，请选择其它方式。");
                        }
                        var collection = orderModel.CollectionRelations.FirstOrDefault()?.Collection;
                        if (collection == null)
                        {
                            throw new ResponseException("无法找到订单的支付方式，请检查重试。");
                        }
                        //判断支付接口类型
                        var pay = await _context.Set<Payment>().FirstOrDefaultAsync(x => x.Id == collection.PaymentId);
                        if (pay == null)
                        {
                            throw new ResponseException("支付方式有误，请检查重试。");
                        }
                        if (pay.ProviderType == 0)
                        {
                            throw new ResponseException("此订单是线下支付，无法原路返回，请检查重试。");
                        }
                        if (pay.ProviderType == 1)
                        {
                            throw new ResponseException("此订单是余额支付，请选择退回会员账户。");
                        }
                        //微信
                        if (pay.ProviderType == 2)
                        {
                            var refundStatus = await _weChatExecuteService.RefundAsync(new Model.WeChat.WeChatPayRefundDto()
                            {
                                OutTradeNo = collection.TradeNo,
                                OutRefundId = model.Id,
                                PaymentId = collection.PaymentId,
                                Refund = model.RefundAmount,
                                Total = collection.PaymentAmount,
                                Reason = model.ApplyReason
                            });
                            if (!refundStatus)
                            {
                                throw new ResponseException("退款原路返回失败，请检查重试。");
                            }
                        }
                        //支付宝
                        if (pay.ProviderType == 3)
                        {
                            var refundStatus = await _alipayExecuteService.RefundAsync(new Model.Alipay.AlipayRefundDto()
                            {
                                OutTradeNo = collection.TradeNo,
                                OutRefundId = model.Id,
                                PaymentId = collection.PaymentId,
                                Refund = model.RefundAmount,
                                Reason = model.ApplyReason
                            });
                            if (!refundStatus)
                            {
                                throw new ResponseException("退款原路返回失败，请检查重试。");
                            }
                        }
                    }

                    //新增订单日志
                    await _context.Set<OrderLog>().AddAsync(new OrderLog
                    {
                        OrderId = orderModel.Id,
                        OrderNo = orderModel.OrderNo,
                        ActionType = ActionType.Refund.ToString(),
                        AddBy = await _userService.GetUserNameAsync(),
                        AddTime = DateTime.Now,
                        Remark = $"订单[{orderModel.OrderNo}]退款金额:{model.RefundAmount}元"
                    });
                    //修改订单状态
                    if (isAllRefund)
                    {
                        orderModel.RefundStatus = 1;
                        //全部已退则取消订单
                        orderModel.Status = 6;
                    }
                    else
                    {
                        orderModel.RefundStatus = 2;
                    }
                    //修改订单结算金额
                    orderModel.SettleAmount -= model.RefundAmount;
                    //保存订单
                    _context.Set<Orders>().Update(orderModel);

                    //修改退换货状态为3已完成
                    model.HandleTime = DateTime.Now;
                    _context.Set<OrderRefund>().Update(model);
                    //保存到数据库
                    return await this.SaveAsync();
                }
                //拒绝退款
                if (modelDto.HandleStatus == 4)
                {
                    _mapper.Map(modelDto, model);
                    model.HandleTime = DateTime.Now;
                    _context.Set<OrderRefund>().Update(model);
                    return await this.SaveAsync();
                }
            }
            //换货
            if (model.Type == 2)
            {
                //如果0未处理且3同意换货时，修改状态为1待买家发货
                //如果0未处理且4拒绝换货时，修改状态为4拒绝
                if (model.HandleStatus == 0 && (modelDto.HandleStatus == 1 || modelDto.HandleStatus == 4))
                {
                    _mapper.Map(modelDto, model);
                    model.HandleTime = DateTime.Now;
                    _context.Set<OrderRefund>().Update(model);
                    return await this.SaveAsync();
                }
                else
                {
                    throw new ResponseException("单据已处理，请勿重复操作");
                }
            }
            return false;
        }

        /// <summary>
        /// 3.客户发货(客户)
        /// </summary>
        public async Task<bool> BuyDeliveryAsync(Expression<Func<OrderRefund, bool>> funcWhere, OrderRefundBuyDto modelDto, WriteRoRead writeAndRead = WriteRoRead.Write)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库

            //检查快递信息是否正确
            if (await _context.Set<ShopExpress>().FirstOrDefaultAsync(x => x.Id == modelDto.UExpressId) == null)
            {
                throw new ResponseException($"快递信息不正确");
            }
            //获取退换货信息
            var model = await _context.Set<OrderRefund>().FirstOrDefaultAsync(funcWhere);
            if (model == null)
            {
                throw new ResponseException($"申请记录不存在或已删除");
            }
            //如果处理状态不是待买家发货，提示错误
            if (model.HandleStatus != 1)
            {
                throw new ResponseException("商家未处理或已完成，请勿重复操作");
            }
            //DTO映射到源数据
            _mapper.Map(modelDto, model);
            //设置处理状态为2待卖家发货
            model.HandleStatus = 2;
            _context.Set<OrderRefund>().Update(model);
            return await this.SaveAsync();
        }

        /// <summary>
        /// 4.卖家发货(管理员)
        /// </summary>
        public async Task<bool> SellerDeliveryAsync(Expression<Func<OrderRefund, bool>> funcWhere, OrderRefundSellerDto modelDto, WriteRoRead writeAndRead = WriteRoRead.Write)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库

            //检查快递信息是否正确
            if (await _context.Set<ShopExpress>().FirstOrDefaultAsync(x => x.Id == modelDto.SExpressId) == null)
            {
                throw new ResponseException($"快递信息不正确");
            }
            //获取退换货信息
            var model = await _context.Set<OrderRefund>().FirstOrDefaultAsync<OrderRefund>(funcWhere);
            if (model == null)
            {
                throw new ResponseException($"数据不存在或已删除");
            }
            //如果处理状态不是待卖家发货，提示错误
            if (model.HandleStatus != 2)
            {
                throw new ResponseException("买家未寄出或已完成，请勿重复提交");
            }
            //DTO映射到源数据
            _mapper.Map(modelDto, model);
            //设置处理状态为3已完成
            model.HandleStatus = 3;
            _context.Set<OrderRefund>().Update(model);
            return await this.SaveAsync();
        }

        /// <summary>
        /// 根据条件删除记录
        /// </summary>
        public async Task<bool> DeleteAsync(Expression<Func<OrderRefund, bool>> funcWhere, WriteRoRead writeAndRead = WriteRoRead.Write)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库

            var list = await _context.Set<OrderRefund>()
                .Include(x => x.RefundGoods)
                .Include(x => x.RefundAlbums)
                .Where(funcWhere).ToListAsync();
            if (list == null)
            {
                return false;
            }
            foreach (var modelt in list)
            {
                _context.Set<OrderRefund>().Attach(modelt);
            }
            _context.Set<OrderRefund>().RemoveRange(list);
            return await this.SaveAsync();
        }
    }
}
